package main

import (
	"fmt"
	"math/rand"
	"sort"
)

func topic1() {
	fmt.Println("topic1:")
	s1 := make([]int, 3, 4) // 定义一个长度为3，容量为4，类型为[]int的一个切片，里面的值用定义的类型的零值填充
	s2 := append(s1, 1)     // 在slice s1的尾部追加一个元素
	fmt.Printf("s1: %v %p %p len=%d cap=%d\n", s1, &s1, &s1[0], len(s1), cap(s1))
	fmt.Printf("s2: %v %p %p len=%d cap=%d\n", s2, &s2, &s2[0], len(s2), cap(s2))
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// slice s1的长度为3，容量为4，底层数组里的元素是[0 0 0]
	// slice s2底层数组是基于s1的底层数组的末尾添加了一个元素，可以说是s2 和 s1是共享底层数组的，这里s2的长度就是4，容量还是4，数组里面的元素是[0 0 0 1]
	s1[0] = 6 // 这里是修改的话s1和s2的第一的元素都会被修改成6
	s2[1] = 8 // 这里修改会将s1和s2的第二的元素都会被修改成6
	s2[3] = 9 // 这里修改的是s2的第四个元素，对s1没有影响，这时的s2的第四个元素的值就被修改成9了
	fmt.Printf("s1: %v %p %p len=%d cap=%d\n", s1, &s1, &s1[0], len(s1), cap(s1))
	fmt.Printf("s2: %v %p %p len=%d cap=%d\n", s2, &s2, &s2[0], len(s2), cap(s2))
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 因为s1和s2这两个切片底层是同一个数组，只不过s1和s2的长度不一样，如果要修改s1或s2中索引为[0,len[s1]-1]这个范围的元素时，这时就会影响到s1和s2这个范围的元素；但是这里修改s2中索引为len(s2)-1时，这时的修改就对s1是没有啥影响的。
	s2 = append(s2, 10)
	fmt.Printf("s1: %v %p %p len=%d cap=%d\n", s1, &s1, &s1[0], len(s1), cap(s1))
	fmt.Printf("s2: %v %p %p len=%d cap=%d\n", s2, &s2, &s2[0], len(s2), cap(s2))
	// 由于s2的长度和容量是一样了，如果这时还要向s2添加元素的话，就会超过当前的容量了，会触发底层数组的扩容，当切片当前的长度+新增的个数>cap时就需要扩容
	// 扩容后就会生成一个新的底层数组，s2这时就使用新的这个底层数组，将之前旧的元素复制到新的数组，然后在追加新的元素
	// 这时的s1还是使用的原来的底层数组，s2就使用新的底层数组了，而且长度为5，容量在原有的基础上翻一倍
}

func topic2() {
	fmt.Println("topic2:")
	var a = [8]int{1, 4, 9, 16, 2, 5, 10, 15} // 定义一个数组，长度为8，容量也为8
	var sums []int                            // 定义一个长度、容量为0的切片
	fmt.Print("生成新的切片为：")
	for i := 0; i < len(a)-1; i++ { // 索引是从0开始的，前面定义的数组的长度为8，末尾的值的索引也就是7，这里就定义界限就到数组长度-1
		sum := a[i] + a[i+1]     // 定义一个变量存放数组相邻两项的和的值
		sums = append(sums, sum) // 在切片的尾部追加元素，加一个元素就会使长度加1
	}
	fmt.Println(sums)
}

func topic3() {
	fmt.Println("topic3:")
	// 生成100个随机整数
	nums := make([]int, 100)
	for i := 0; i < 100; i++ {
		nums[i] = rand.Intn(201) - 100
	}

	// 对生成的整数进行降序排序
	sort.Sort(sort.Reverse(sort.IntSlice(nums)))

	// 统计生成的整数重复次数
	counts := make(map[int]int)
	for _, num := range nums {
		counts[num]++
	}

	// 将生成的随机数降序并将统计的个数打印出来
	for _, num := range nums {
		if counts[num] > 0 {
			fmt.Printf("%d： (出现的次数为%d)\n", num, counts[num])
		}
	}
}

func main() {
	// 1、请问s1、s2内各有什么元素？s1修改一个元素会影响s2吗？s2修改一个元素会影响s1吗？s2在添加一个元素会怎样？
	topic1()
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 2、有一个数组[1,4,9,16,2,5,10,15],生成新的切片，要求新的切片元素是数组相邻两项的和
	topic2()
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	// 3、数字重复统计,随机产生100个整数,数字范围[-100,100],降序输出这些生成的数字并打印其重复的次数
	topic3()
	fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
}
// 批改意见
// 1. 前面两题都完成的很不错，第3题也自己尝试一下
// 更新忘记提交的第三题的代码
